import uuid from 'uuid/v4';
import produce from 'immer';
import React, {useEffect, createContext, useContext, useCallback} from "react";
import type { FC, DragEvent, PropsWithChildren, Dispatch, CSSProperties } from "react";
import type {IComponent} from "@bastet/widgets";
import { DroppableComponent } from '@bastet/widgets';
import {getClientRect, getStore} from "@bastet/utils";
import {BuilderContainer} from "./BuilderContainer";
import {BuilderWidget} from "./BuilderWidget";
import {createFunc} from "../../hooks/func";
import './style.less';

export const Context = createContext(getStore('debugging'))

function useResizeEditor (defaultStyle: CSSProperties): CSSProperties {
  const [style, setStyle ] = React.useState(defaultStyle)
  function resizeBuilderEditor () {
    const { width, height }: any = getClientRect('#builder-container') || {}
    setStyle({ ...style, minWidth: width - 40, minHeight: height - 40 })
  }

  useEffect(() => {
    resizeBuilderEditor ()
    document.addEventListener('resize', resizeBuilderEditor, false)
    return () => {
      document.removeEventListener('resize', resizeBuilderEditor, false)
    }
  }, [] as React.DependencyList)

  return style
}

type IBuilderEditor = {
  activated?: string;
  widgets: Map<string, any>;
  defaultStyle: CSSProperties;
  state: any;
  dispatch: Dispatch<any>;
  changeField: Dispatch<any>;

  onClick: (ev: React.MouseEvent<Element>, arg?: any) => void;
  onSave: (ev?: React.MouseEvent<Element>) => void;
  onCancel: (ev: React.MouseEvent<Element>) => void;
  onDevelop: (ev: React.MouseEvent<Element>) => void;
}

const BuilderTool = ({ onSave, onCancel, onDevelop }: any) => {
  const debugging = useContext(Context)
  const btns = [
    <div className="builder-tool-btn builder-tool-save" onClick={onSave} key="saveMeratial">保存素材</div>,
    <div className="builder-tool-btn builder-tool-save" onClick={onSave} key="saveScene">保存场景</div>,
    <div className="builder-tool-btn builder-tool-cancel" onClick={onCancel} key="cancel">取消</div>
  ]

  if ((import.meta as any).env.DEV) {
    btns.push(
      <div
        className="builder-tool-btn builder-tool-develop"
        onClick={onDevelop}
        key="develop">
        { debugging ? '取消' : '' }调试
      </div>
    )
  }

  return (
    <div className="builder-tool-bar">{btns}</div>
  )
}

export const BuilderEditor: FC<PropsWithChildren<IBuilderEditor>> = (
  {
    activated,
    widgets,
    defaultStyle,
    state,
    dispatch: setDashboardState,
    changeField,
    onClick,
    onSave,
    onCancel,
    onDevelop,
  }
) => {
  const style = useResizeEditor(defaultStyle)
  const data = { id: 'builderEditor', name: 'builder-editor', path: 'playground'}

  const onDrop = (event: DragEvent <Element>, arg: any) => {
    const { originIndex = 0, data, targetIndex } = arg;
    // 目标下标转数组
    const targetIndexArray = targetIndex?.split('-') || [];
    // 插入位置
    const index = targetIndexArray.pop();

    console.log('onDrop: => ', arg, originIndex, targetIndex);
    try {
      let isUpdate = true;
      const nextState: any = produce(state, (draft: any) => {
        const func = createFunc(targetIndexArray as any);
        let prevComponents: any;
        console.log(func)
        func(draft, (components: IComponent[]) => {
          console.log('components', components)
          if (!components) return  components
          if (index <= 0) {
            components.unshift(data)
          } else if (index > 0) {
            components.splice(+index, 0, data)
          }

          prevComponents = components;
          return components
        })

        if (originIndex) {
          // 来源下标转数组
          const originIndexArray = originIndex?.split('-') || [];
          // 删除来源目标下标位置
          const removeIndex = originIndexArray.pop();
          const removeFunc = createFunc(originIndexArray as any);

          // 去掉最后一位
          // 0 -> ''
          // 0-1 -> '0'
          // 0-1-3 -> '0-1'
          removeFunc(draft, (components: IComponent[]) => {
            if (!components) return  components
            components.splice(removeIndex, 1);

            console.log('prevComponents', prevComponents, components)
            console.log('prevComponents', prevComponents.toString(), components.toString(), prevComponents.toString() === components.toString())
            if (prevComponents.toString() === components.toString()) {
              isUpdate = false;
            }
            console.log('components', components)
            return components
          })
        }
      });
      console.log(nextState)
      if (isUpdate) {
        setTimeout(() => {
          if (nextState !== state) {
            setDashboardState(nextState)
            // this.setState({ dashboardState:  } as any);
          }
        }, 200)
      }
    } catch (error) {
      return console.log(error)
    } finally {
      // 清空拖拽的数据
      event.dataTransfer.clearData();
    }
  }
  const onBuilderEditorSave = useCallback((event: any) => {
    if (event.ctrlKey && (event.keyCode === 83 || event.key === 's')) {
      event.stopPropagation()
      event.preventDefault()
      onSave && onSave()
    }
  }, [])

  useEffect(() => {
    window.addEventListener('keydown', onBuilderEditorSave , false)
    return () => {
      document.removeEventListener('keydown', onBuilderEditorSave, false)
    }
  }, [] as React.DependencyList)

  // console.log('BuilderEditor: => ', state, state.values());
  return (
    <BuilderContainer
      style={style}
      builderTool={() => (
        <BuilderTool
          onSave={onSave}
          onCancel={onCancel}
          onDevelop={onDevelop}
        />
      )}
    >
      <DroppableComponent
        key={`root-playground`}
        data={data}
        operate={false}
        className="builder-editor"
        style={style}
        onClick={(ev) => onClick(ev, data)}
        onDrop={onDrop}
      >
        {
          state.map((child: IComponent, index: number) => {
            return (
              <BuilderWidget
                key={`${ uuid() }_${ index }_${ child.id }`}
                index={`${index}`}
                activated={activated}
                widgets={widgets}
                onDrop={onDrop}
                onClick={onClick}
                data={child}
                dispatch={setDashboardState}
                changeField={changeField}
              />
            )
          })
        }
      </DroppableComponent>
    </BuilderContainer>
  )
}